import { ConstantEnum } from '@libs/common/enums';
import {
  BaseRepository,
  indexPaginateBuilder,
  showBuilderEntity,
} from '@libs/common/repository';
import { Inject, Injectable } from '@nestjs/common';
import { plainToInstance } from 'class-transformer';
import { DataSource, Equal, In } from 'typeorm';

import { MemberService } from '@/dingding/member/member.service';

import { OvertimeApplyService } from '../overtime-apply/overtime-apply.service';
import { OvertimeLogService } from '../overtime-log/overtime-log.service';
import {
  CreateOvertimeDto,
  DeleteOvertimeDto,
  FindOneByIdOvertimeDto,
  IndexOvertimeDto,
  ShowOvertimeDto,
  SyncOvertimeDto,
  UpdateOvertimeDto,
} from './dto/overtime.dto';
import { Overtime } from './entities/overtime.entity';

@Injectable()
export class OvertimeService extends BaseRepository {
  constructor(
    @Inject(ConstantEnum.DB_DATA_SOURCE_MANAGER) dataSource: DataSource,
  ) {
    super(dataSource);
  }

  protected repository = this.getRepository(Overtime);

  protected repositoryManager = () => this.getRepository(Overtime);

  @Inject(MemberService)
  private memberService: MemberService;

  @Inject(OvertimeLogService)
  private overtimeLogService: OvertimeLogService;

  @Inject(OvertimeApplyService)
  private overtimeApplyService: OvertimeApplyService;

  async index(dto: IndexOvertimeDto) {
    const res = await indexPaginateBuilder({
      dto,
      repository: this.repository,
    });
    return res;
  }

  show<D extends ShowOvertimeDto = ShowOvertimeDto>(dto: D) {
    return showBuilderEntity(this.repository, dto);
  }

  async delete(dto: DeleteOvertimeDto) {
    const { id, ids } = dto;
    if (id) {
      await this.repositoryManager().delete({ id: Equal(id) });
    } else if (ids) {
      await this.repositoryManager().delete({ id: In(ids) });
    }
    return;
  }

  update(dto: UpdateOvertimeDto) {
    const dtos = Array.isArray(dto) ? dto : [dto];
    const entities = plainToInstance(Overtime, dtos);

    return this.repositoryManager().save(entities);
  }

  async create(dto: CreateOvertimeDto) {
    const entity = this.repositoryManager().create(
      plainToInstance(Overtime, dto),
    );
    await this.repositoryManager().insert(entity);
    return entity;
  }

  import() {
    // CODE
  }

  export() {
    // CODE
  }

  switch(id: string, status: boolean) {
    // status 需要在 entity 中定义, 如果没有不需要这个接口
    // return this.repository.update({ id }, { status });
  }

  async sync(dto: SyncOvertimeDto) {
    const user = await this.memberService.findOne({ dingUserId: dto.dingId });

    if (!user) throw new Error(`[${dto.dingId}] 不存在`);

    /** 总计时长 */
    const totalTime = await this.overtimeLogService.countTime({
      dingId: dto.dingId,
    });
    /** 已用时长 */
    const usedTime = await this.overtimeApplyService.countTime({
      dingId: dto.dingId,
    });

    let remainTime = Math.floor((totalTime - usedTime) * 100) / 100;

    if (remainTime < 0) remainTime = 0;

    const record = await this.repository.findOneBy({ dingId: dto.dingId });

    if (record) {
      await this.update({ ...record, totalTime, usedTime, remainTime });
      return record;
    }

    return this.create({
      userName: user.name,
      userId: user.userId,
      dingId: dto.dingId,
      totalTime: totalTime,
      usedTime: usedTime,
      remainTime: remainTime,
    });
  }

  /** 查询用户加班记录 */
  async findOneById(dto: FindOneByIdOvertimeDto) {
    if (!dto.dingId) return null;

    await this.sync({ dingId: dto.dingId });

    return this.repository.findOneBy({
      dingId: dto.dingId,
    });
  }
}
